package com.haoxuer.discover.weibo.rest.resource;

import com.haoxuer.discover.config.data.entity.User;
import com.haoxuer.discover.config.utils.ConverResourceUtils;
import com.haoxuer.discover.data.enums.StoreState;
import com.haoxuer.discover.data.page.Filter;
import com.haoxuer.discover.data.page.Order;
import com.haoxuer.discover.data.page.Page;
import com.haoxuer.discover.data.page.Pageable;
import com.haoxuer.discover.filter.base.HandlerFilterProxy;
import com.haoxuer.discover.filter.base.MockFilterChain;
import com.haoxuer.discover.filter.base.RestRequest;
import com.haoxuer.discover.filter.common.Handler;
import com.haoxuer.discover.filter.common.HandlerResponse;
import com.haoxuer.discover.rest.base.ResponseObject;
import com.haoxuer.discover.user.service.UserTokenService;
import com.haoxuer.discover.weibo.api.apis.WeiBoApi;
import com.haoxuer.discover.weibo.api.domain.page.WeiBoCommentPage;
import com.haoxuer.discover.weibo.api.domain.page.WeiBoLikePage;
import com.haoxuer.discover.weibo.api.domain.page.WeiboPage;
import com.haoxuer.discover.weibo.api.domain.request.*;
import com.haoxuer.discover.weibo.api.domain.response.WeiBoResponse;
import com.haoxuer.discover.weibo.data.dao.*;
import com.haoxuer.discover.weibo.data.entity.*;
import com.haoxuer.discover.weibo.data.enums.FileType;
import com.haoxuer.discover.weibo.data.enums.LikeType;
import com.haoxuer.discover.weibo.data.enums.WeiBoType;
import com.haoxuer.discover.weibo.rest.adapter.ResponseAdapter;
import com.haoxuer.discover.weibo.rest.conver.*;
import com.haoxuer.discover.weibo.rest.filter.CommentCheckFilter;
import com.haoxuer.discover.weibo.rest.filter.FilterProxy;
import com.haoxuer.discover.weibo.rest.filter.TimeCheckFilter;
import com.haoxuer.discover.weibo.rest.filter.WeiboCheckFilter;
import com.vdurmont.emoji.EmojiParser;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


@Scope("prototype")
@Component
@Transactional
public class WeiBoResource implements WeiBoApi, ApplicationContextAware {

  private ApplicationContext context;


  @Autowired
  ChannelDao channelDao;

  @Autowired
  WeiBoChannelDao weiBoChannelDao;

  @Autowired
  UserTokenService tokenService;

  @Autowired
  WeiBoDao weiBoDao;

  @Autowired
  WeiboFileDao fileDao;

  @Autowired
  WeiBoLikeDao likeDao;

  private void handles(RestRequest handleRequest, HandlerResponse response, Handler handler, FilterProxy... filters) {
    MockFilterChain chain = new MockFilterChain();
    if (filters != null && filters.length > 0) {
      for (FilterProxy filter : filters) {
        chain.addFilter(filter);
      }
    }
    chain.addFilter(new HandlerFilterProxy(handler));
    chain.doFilter(handleRequest, response);
  }

  @Override
  public ResponseObject post(WeiboPostRequest request) {
    ResponseObject result = new ResponseObject();

    RestRequest restRequest = new RestRequest();
    restRequest.setAttribute("request", request);

    Handler handler = (handlerRequest, response) -> {
      User user = (User) handlerRequest.getAttribute("user");
      WeiBo bean = new WeiBo();
      String note = EmojiParser.parseToAliases(request.getNote());
      bean.setNote(note);
      bean.setUser(user);
      bean.setStoreState(StoreState.normal);
      bean.setWeiBoType(WeiBoType.first);
      bean.setLikes(0L);
      bean.setForwards(0L);
      bean.setReplys(0L);
      weiBoDao.save(bean);
      storeImages(request, bean);
      if (request.getChannels() != null) {
        for (String channel : request.getChannels()) {
          if (StringUtils.isEmpty(channel)) {
            continue;
          }
          Channel item = channelDao.channel(channel);
          WeiBoChannel topicChannel = new WeiBoChannel();
          topicChannel.setChannel(item);
          topicChannel.setWeiBo(bean);
          weiBoChannelDao.save(topicChannel);
        }
      }
    };
    handles(restRequest, new ResponseAdapter(result), handler, context.getBean(TimeCheckFilter.class));
    return result;
  }

  @Override
  public WeiBoResponse findById(FindByIdRequest request) {
    WeiBoResponse result = new WeiBoResponse();
    WeiBo weiBo = weiBoDao.findById(request.getId());
    if (weiBo == null) {
      result.setCode(501);
      result.setMsg("无效id");
      return result;
    }
    result = new WeiBoResponseConver().conver(weiBo);
    PageByIdRequest commentRequest = new PageByIdRequest();
    commentRequest.setId(request.getId());
    WeiBoCommentPage page = pageForComment(commentRequest);
    result.setCommentList(page.getList());
    WeiBoLikePage likePage = pageForLike(commentRequest);
    result.setLikeList(likePage.getList());
    if (StringUtils.hasText(request.getUserToken())) {
      Long uid = tokenService.user(request.getUserToken());
      Boolean liked = likeDao.liked(request.getId(), uid);
      result.setLiked(liked);
    } else {
      result.setLiked(false);
    }

    return result;
  }

  @Override
  public WeiBoCommentPage pageForComment(PageByIdRequest request) {
    WeiBoCommentPage result = new WeiBoCommentPage();
    Pageable pageable = new PageableConver().conver(request);
    pageable.getOrders().add(Order.desc("id"));
    pageable.getFilters().add(Filter.eq("root.id", request.getId()));
    pageable.getFilters().add(Filter.eq("weiBoType", WeiBoType.reply));
    pageable.getFilters().add(Filter.eq("storeState", StoreState.normal));

    Page<WeiBo> page = weiBoDao.page(pageable);
    ConverResourceUtils.converPage(result, page, new WeiBoCommentSimpleConver());
    return result;
  }

  @Override
  public WeiBoLikePage pageForLike(PageByIdRequest request) {
    WeiBoLikePage result = new WeiBoLikePage();
    Pageable pageable = new PageableConver().conver(request);
    pageable.getFilters().add(Filter.eq("weiBo.id", request.getId()));
    pageable.getFilters().add(Filter.eq("likeType", LikeType.like));
    pageable.getOrders().add(Order.desc("id"));
    Page<WeiBoLike> page = likeDao.page(pageable);
    ConverResourceUtils.converPage(result, page, new WeiBoLikeSimpleConver());
    return result;
  }

  private void storeImages(WeiboPostRequest request, WeiBo bean) {
    if (request.getImages() != null) {
      for (String image : request.getImages()) {
        if (StringUtils.isEmpty(image)) {
          continue;
        }
        WeiboFile file = new WeiboFile();
        file.setFileType(FileType.image);
        file.setWeiBo(bean);
        file.setUrl(image);
        fileDao.save(file);
      }
    }
  }

  @Override
  public WeiboPage page(WeiboPageRequest request) {
    WeiboPage result = new WeiboPage();
    Pageable pageable = new PageableConver().conver(request);
    pageable.getOrders().add(Order.desc("id"));
    pageable.getFilters().add(Filter.eq("weiBoType", WeiBoType.first));
    pageable.getFilters().add(Filter.eq("storeState", StoreState.normal));

    Page<WeiBo> page = weiBoDao.page(pageable);
    ConverResourceUtils.converPage(result, page, new WeiBoSimpleConver());
    return result;
  }

  @Override
  public WeiboPage myPub(WeiboPageRequest request) {
    Long uid = tokenService.user(request.getUserToken());

    WeiboPage result = new WeiboPage();
    Pageable pageable = new PageableConver().conver(request);
    pageable.getOrders().add(Order.desc("id"));
    pageable.getFilters().add(Filter.eq("user.id", uid));
    pageable.getFilters().add(Filter.eq("weiBoType", WeiBoType.first));
    pageable.getFilters().add(Filter.eq("storeState", StoreState.normal));

    Page<WeiBo> page = weiBoDao.page(pageable);
    ConverResourceUtils.converPage(result, page, new WeiBoSimpleConver());
    return result;
  }

  @Override
  public ResponseObject like(FindByIdRequest request) {
    return toggle(request, LikeType.like);
  }

  private ResponseObject toggle(FindByIdRequest request, LikeType likeType) {

    ResponseObject result = new ResponseObject();

    RestRequest restRequest = new RestRequest();
    restRequest.setAttribute("request", request);
    Handler handler = (handlerRequest, response) -> {
      User user = (User) handlerRequest.getAttribute("user");
      WeiBo root = (WeiBo) handlerRequest.getAttribute("root");
      WeiBoLike like = likeDao.findByUser(user.getId(), root.getId());
      if (like == null) {
        like = new WeiBoLike();
        like.setUser(user);
        like.setWeiBo(root);
        like.setLikeType(likeType);
        likeDao.save(like);
      }
      like.setLikeType(likeType);
      weiBoDao.countLike(request.getId());
    };
    handles(restRequest, new ResponseAdapter(result), handler, context.getBean(WeiboCheckFilter.class));
    return result;
  }

  @Override
  public ResponseObject unLike(FindByIdRequest request) {
    return toggle(request, LikeType.init);
  }

  @Override
  public ResponseObject comment(WeiboCommentRequest request) {
    ResponseObject result = new ResponseObject();

    RestRequest restRequest = new RestRequest();
    restRequest.setAttribute("request", request);
    Handler handler = (handlerRequest, response) -> {
      User user = (User) handlerRequest.getAttribute("user");
      WeiBo root = (WeiBo) handlerRequest.getAttribute("root");
      WeiBo bean = new WeiBo();
      String note = EmojiParser.parseToAliases(request.getNote());
      bean.setNote(note);
      bean.setUser(user);
      bean.setStoreState(StoreState.normal);
      bean.setWeiBoType(WeiBoType.reply);
      bean.setLikes(0L);
      bean.setForwards(0L);
      bean.setReplys(0L);
      bean.setRoot(root);
      weiBoDao.save(bean);
      weiBoDao.countComment(request.getId());
      storeImages(request, bean);
    };
    handles(restRequest, new ResponseAdapter(result), handler,
      context.getBean(TimeCheckFilter.class), context.getBean(CommentCheckFilter.class));
    return result;

  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.context = applicationContext;
  }
}
